craftstudiofandomcom_fr-20200214-history
Tutoriels/Aperçu du Lua pour programmeur confirmé
Ce tutoriel sur le Lua s'adresse aux personnes sachant déjà programmer dans un autre language de programmation. Il donne une rapide vue d'ensemble du Lua et de ses principales différences avec la plupart des autres langages. Vous pouvez également consulter ce document (.pdf) ou les tutoriaux officiels (en anglais). Général Il n'y a pas de point virgule à la fin des instructions. Un commentaire uniligne débute par deux tirets --. Un block de commentaire multiligne est entouré des expressions : -- -- Vous pouvez imbriquer des blocs de commentaires en ajoutant un ou plusieurs signes égaux = entre les crochets. --[[ ceci est un --[=[ commentaire sur plusieurs ]=]-- lignes ]]-- La fonction pour afficher du texte dans la console se nomme print(exp). Elle peut afficher plusieurs valeurs à la fois (sans les concaténer) si celles-ci sont séparées par une virgule. print(valeur1, valeur2, valeur3) -- va afficher les trois valeurs sur la même ligne, séparées par un espace conséquent Les variables sont dynamiquement typées. Les fonctions n'ont pas de type de retour. Exemple de déclaration d'une variable (voir plus bas pour les fonctions) : nomVariable = valeur On peut déclarer plusieurs variables en une seule ligne. Attention au piège, la syntaxe n'est pas tout à fait la même que dans les autres langages : variable1, variable2, variable3 = valeur1, valeur2, valeur3 -- la variable1 possède la valeur1, la variable2 possède la valeur2 et la variable3 possède la valeur3 Il n'y a que 7 types de donnée : String, Number, Boolean, Table, Fonction, UserData et Thread. Lorsqu'une variable ne contient rien ou n'existe pas (ce qui revient au même), sa valeur est nil (l'équivalent de null). La fonction type(exp)''retourne le type de l'expression en argument. La fonction ''error(d'erreur) affiche le message d'erreur dans la console et stoppe le script. Strings On peut utiliser des guillemets doubles ou simples lorsque la chaine est sur une seule ligne. On ne peut échaper des caractères à l'intérieur de la chaîne que dans ce cas (string sur une seule ligne). Pour écrire un string sur plusieurs lignes on peut utiliser des double crochets (comme avec les commentaires). On ne peut pas échapper de caractères avec cette syntaxe. Comme avec les commentaires, il est possible d'ajouter des signes égaux entre les crochets afin de les imbriquer. ceci est un string écrit sur plusieurs lignes La concaténation utilise deux points .. : "un string " .. 'concaténé' Les nombres sont transformés automatiquement en string dès que nécessaire (affichage, concaténation). Ce qui n'est pas le cas avec les booléens qui nécessitent d'utiliser la fonction tostring(exp) "100"..100 -- équivant à "100100" "malo"..tostring(true) -- équivaut à "malotrue" Accéder à la longueur d'un string se fait en fesant précéder la variable d'un croisillon (#). texte = "un string" print(#texte) -- affichera 9 Numbers Ce seul type est utilisé pour tous chiffres ou nombres. Puissance de 10 : 1.2345e6 -- equivaut à 1234500 543.21E8 -- equivaut à 54321000000 2.56e-4 -- equivaut à 0.000256 La fonction tonumber(string)''permet de convertir de String à Number. Utiliser un opérateur arithmétique avec un string et un nombre tentera automatiquement de convertir le string en nombre : "100"+100 -- équivaut à 200. Les opérateurs +=, -=, *=, /=, ++ et -- '''n'existent pas'. Seuls +, -, *, /, % et ^ existent. Boucles while condition do corps end repeat corps until condition for variable = début, fin, increment do corps end increment, la taille du pas de l'itération, est un argument optionnel, et vaut 1 par défaut. Voir la section table plus bas pour l'utilisation de for() avec les tables et les itérateurs pairs() et ipairs() Une boucle peut être stoppée par le mot clé break, mais continue n'existe pas. Conditions if condition then corps elseif condition then corps else corps end elif et else sont bien sur optionnels. Il n'y a pas d'opérateur ternaire. Opérateurs de comparaison : , ~= (équivalent de !=), <, <=, >, >=, not (équivalent de !), and (&&) et or (||). Les opérateurs ou ~ n'existent pas. < et > fonctionnent sur des strings : ("abc" < "def") est vrai. Tout ce qui est ni false ni nil est true. En conséquence 0 ou les string vides sont équivalents à true. De plus false est équivalent à nil, mais (false nil) est faux. (not nil) est vrai. Les comparaisons sur les tables ou les fonctions comparent l'emplacement en mémoire et non le contenu. t = {} t2 = t (t t2) est vrai car dans ce cas t et t2 font référencesà la même table. {} {} est faux car ce sont deux tables différentes. De la même manière (t {}) ou (t2 {}) sont faux. Les opérateurs de comparaison ne coercent pas (ne changent pas le type des données comparées) : ("10" 10) est faux mais (tonumber("10") 10) est vrai. Les opérateurs and et or''ont un comportement différent des autres languages. En effet (exp1 and exp2) ne retourne pas forcément un booléen. And retourne la valeur de gauche, si celle-ci est équivalente à false, ou retourne la valeur de droite si la valeur de gauche est équivalent à vrai. Or fait l'inverse, il retourne la valeur de gauche si elle est équivalente à true, sinon retourne la valeur de droite. Tables Les tables sont des collections flexibles et fourre-tout. Les tables peuvent contenir n'importe quels types de donnée tant en tant que clé qu'en tant que valeur. '''Les index numériques commencent à 1 et non à 0 !' maTable = { 5, "string", false} print(maTable1) -- affiche 5 print(maTable4) -- affiche nil Pour ajouter une valeur à la fin d'une table : table.insert(nomDeLaTable, valeur) -- noter que la fonction ne retourne rien, elle agit sur la table par référence table 'est le nom de la variable globale fournie par le Lua qui contient les fonctions relatives aux tables. Pour intercaler une valeur à un index donné, sans écraser la valeur présente à cet index, en décalant l'index des valeurs qui sont "derrière" : table.insert(nomDeLaTable, index, valeur) Pour retirer une valeur en décalant l'index des autres valeurs : table.remove(nomDeLaTable, index) Pour supprimer une valeur sans décaler : nomDeLaTableindex = nil Les clés non numériques ne doivent pas commencer par un nombre. Lorsque la clé est un string, il y a deux syntaxes équivalentes : maTable = { avec espace" = valeur, cleSansEspace = valeur} maTableavec espace" maTable.cleSansEspace -- ou encore maTable."cleSansEspace" Notez que les crochets peuvent également s'utiliser avec les nombres : maTable = { 2 = valeur } -- évite que la valeur soit par défaut attribuée à l'index 1 Pour parcourir toutes les clés numériques d'une table, vous devez utiliser une boucle for avec l'itérateur ''ipairs() : for cle,valeur in ipairs(nomDeLaTable) do print (cle, valeur) end -- ou bien for cle=1, #nomDeLaTable do -- #nomDeLaTable retourne la taille de la table (voir juste en dessous) print(cle, nomDeLaTablecle) end '''Attention ! L'opérateur # appliqué à une table ne retourne pas nécessairement le nombre de clés dont la valeur est non nil ! Pour parcourir toutes les clés (numériques ou non) d'une table, vous devez utiliser cette fois l'itérateur pairs() : for cle,valeur in pairs(nomDeLaTable) do print(cle, valeur) end Fonctions Les fonctions ne sont qu'un type de donnée. Créer une fonction revient à créer une variable du même nom de type "fonction". On peut également utiliser les fonctions comme clé ou valeur dans des tables ou passer des fonctions en argument d'autres fonctions ou retourner des fonctions, ou encore créer des fonctions en cours d'exécution. function UneFonction() corps end -- revient à écrire UneFoncton = function() corps end -- on peut aussi utiliser des fonctions anonymes var = (function(n) return n*2 end)(4) -- var vaut 8 Une fonction en Lua ne peut pas être surchargée et les arguments ne peuvent avoir ni de valeur ni de type par défaut mais les fonctions peuvent posséder un nombre variable d'argument. Il suffit que le dernier argument soit trois points : function(arg1, ...). La fonction a alors accès à une table "arg" qui contient les arguments optionnels. function UneFonction(...) print(arg) end UneFonction('deux', 3, 4) -- affichera : deux 3 4 UneFonction(20, "trente") -- affichera : 20 trente Si vous appelez une fonction avec trop d'arguments, les argument surnuméraires seront simplement ignorés. À l'inverse les arguments d'une fonction auxquels vous ne passez pas de valeur lors de l'appel valent nil dans la fonction. unpack() est une fonction qui transforme une table en une liste de valeur (prises dans la table) : maTable = {1, 2, 3} -- unpack(maTable) reviens exactement à écrire "1, 2, 3" -- quelle que soit la situation : -- définir plusieur variables à partir de la table : var1, var2, var3 = unpack(table) -- var1 vaut 1, var2 vaut 2 et var3 vaut 3 UneFonction(unpack(maTable), 4) -- est équivalent à UneFonction(1, 2, 3, 4) Une fonction peut retourner plusieurs valeurs à la fois, en les séparant par une virgule : function() return valeur1, valeur2 end foo = function() return 1, 2, 3 end var1, var2, var3 = foo() -- var1 vaut 1... Lorsqu'une fonction retourne plusieurs valeurs, celles-ci peuvent être récupérées sous forme de table en entourant l'appel à la fonction par des crochets : maTable = {foo()} print(unpack(maTable)) -- affiche "1 2 3" -- c'est tout à fait équivalent à écrire maTable = {1, 2, 3} -- si one ne veut qu'une seule valeur, on peut écrire : var2 = ( {foo()} )2 -- ce qui revient à écrire maTable2 -- si on ne veut que la première valeur, on peut entourer l'appel de la fonction avec des parenthèses : var1 = (foo()) Portée des variables Deux visibilités : globale et locale. Par défaut, toute variable est globale, c'est à dire qu'elle est accessible dans tous les scripts de votre application (du moins sous CraftStudio). Une variable locale (précédée du mot clé local) est accessible partout dans le bloc ou elle est crééé, ainsi que dans tous les blocs de portée inférieure. C'est le comportement classique d'une variable dans les autres languages de programmation. Ainsi une variable locale définie dans un script ne sera accessible que dans ce script. De la même manière, une variable locale définie dans une fonction ne sera pas accessible en dehors de celle-ci. Sous CraftStudio, on peut également définir une troisème visibilité publique pour les variables crééés sur self à l'intérieur de fonctions crééés sur Behavior. Ces variables seront alors accessible via une instance d'un script, telles que le sont les membres publics d'un objet. POO Le Lua ne possède pas de notion de classe (et tout ce qui va avec), il n'y a donc pas de POO au même sens que dans les autres languages orientés objet. Néanmoins la notion d'object existe, se sont simplement des tables qui typiquement contiendront au moins des fonctions et seront utilisée de manière orientée objet. Object = { Fonction1 = function() end } Object.membre = "valeur" -- il y a en tout 4 syntaxes pour définir des fonctions dans un objet/une table. Les trois premières sont équivalentes. -- La première consiste à définir la fonction lors de la création de la table, comme pour Fonction1 plus haut -- La deuxième : Object.Fonction2 = function() end -- La troisième : function Object.Fonction3() end -- Et enfin la quatrième : -- L'important ici est le double point entre le nom de l'object et celui de la fonction function Object:Fonction4() -- self end Le double point a pour effet de faire exister à l'intérieur de la fonction la variable self. Mais attention ! Cette variable ne représente pas forcément l'objet. Self prendra toujours la valeur du premier argument passé à la fonction, qui lui, dépend de la manière dont la fonction est appelée. En effet, appeler une fonction en séparant le nom de l'object du nom de la fonction par un double point place l'objet comme premier argument (les autres sont simplement décalés) : -- lors de la déclaration : function Object:Fonction(arg1, arg2) end -- est équivalent à écrire function Object.Fonction(self, arg1, arg2) end -- lors de l'appel : Object:Fonction("arg1", "arg2") -- est équivalent à écrire Object.Fonction(Object, "arg1", "arg2") Donc self représente l'objet si et uniquement si la fonction est créé et appelée avec un double point. Dans le cadre des objets, c'est une bonne pratique de systématiquement utiliser le double point. Metamethods et Metatbles Les métaméthodes sont l'équivalent des méthodes magiques et sont essentiellement utilisées pour la surcharge d'opérateurs ou en combinaison avec les metatables. Une metatable est une table qui a vocation a être appliquéeà un ou plusieurs objects, mais n'est pas copiée dans les objects. Un avantage des métatables est qu'une modification (d'une métatable) est imédiatement accessible à tous les objects sur lesquels la métatable s'aplique. Une mététable sera ainsi typiquement utilisée pour contenir tous les éléments qui ne dépendent pas d'une copie d'un object en particulier, notament les fonctions. Les metamethods et metatables permettent également de partiellement simuler des comportements typiques (héritage, ...) de la POO. Pour ces deux sujets, je vous renvoie vers les tutoriels officiels. Catégorie:Tutoriels